package com.streaminggbs.common.config;

import com.alibaba.fastjson.JSONObject;
import com.streaminggbs.common.constants.Constants;
import com.streaminggbs.common.mongodb.DeviceCoordinateModel;
import com.streaminggbs.common.utils.SpringUtil;
import com.streaminggbs.entity.DeviceInfo;
import com.streaminggbs.entity.SysParamSet;
import com.streaminggbs.interfaces.DeviceInfoService;
import com.streaminggbs.interfaces.Gb28181Service;
import com.streaminggbs.interfaces.MongoService;
import com.streaminggbs.interfaces.SysParamSetService;
import com.streaminggbs.service.DeviceInfoServiceImpl;
import com.streaminggbs.service.Gb28181ServiceImpl;
import com.streaminggbs.service.MongoServiceImpl;
import com.streaminggbs.service.SysParamSetServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import java.net.URI;
import java.util.Date;
import java.util.concurrent.CompletableFuture;

@Component
@ClientEndpoint
@Slf4j
public class DeviceStatusWebsocketConfig{

    /**初始化监听对象*/
    public static Integer retryNum = 0;
    @Value("${device.status.ws.url}")
    public String deviceStatusWsUrl;
    @Autowired
    public DeviceInfoService deviceInfoService;
    public static String deviceStatusWsUrl2;
    public void startJob() {
        deviceStatusWsUrl2 = String.format(deviceStatusWsUrl,SpringUtil.getBean(SysParamSetServiceImpl.class).pick().getVideoServerUrl().split("//")[1]);
        try {
            Thread t = new Thread(new Runnable(){
                @Override
                public void run(){
                    try{
                        // run方法具体重写
                        while (true) {
                            try {
                                WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer();
                                DeviceStatusWebsocketConfig deviceStatusWebsocketConfig = new DeviceStatusWebsocketConfig();
                                webSocketContainer.connectToServer(deviceStatusWebsocketConfig, new URI(deviceStatusWsUrl2));
                                return;
                            } catch (Exception e1) {
                                log.error("", e1);
                            }
                            try {
                                Thread.sleep(300 * 1000);
                            } catch (Exception e2) {
                                log.error("", e2);
                            }
                        }
                    }catch (Exception e){
                        log.error("",e);
                    }
                }});
            t.start();
        }catch (Exception e){
            log.error("",e);
        }
    }
    @OnOpen
    public void onOpen(Session session) {
        log.info("正在重试上下线订阅的次数:{}",retryNum++);
        Gb28181Service gb28181Service = SpringUtil.getBean(Gb28181ServiceImpl.class);
        log.info("[websocket->{}] 上下线订阅连接成功",deviceStatusWsUrl2);
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("[websocket->{}] 上下线订阅收到消息={}",deviceStatusWsUrl2,message);
        CompletableFuture.runAsync(()->{
            log.info("进入异步线程处理数据信息:{},日期:{}",message, DateFormatUtils.format(new Date(),"开始时间yyyy-MM-dd hh:mm:ss"));
            JSONObject jsonObject = JSONObject.parseObject(message);
            // 在线的逻辑
            Gb28181Service gb28181Service = SpringUtil.getBean(Gb28181ServiceImpl.class);
            boolean bol = false;
            if (jsonObject.getString("catalog").equals(Constants.DEVICE_STATUS_ONLINE)) {
                bol = gb28181Service.httpOnLine(jsonObject);
            } else if(jsonObject.getString("catalog").equals(Constants.DEVICE_STATUS_OFFLINE)){
                bol = gb28181Service.httpoffLine(jsonObject);
            } else if(jsonObject.getString("catalog").equals(Constants.DEVICE_LAST_LOCATION)){
                // 如果设备传了坐标需要记录到
                if (jsonObject.containsKey("Info")) {
                    JSONObject info = jsonObject.getJSONObject("Info");
                    // 轨迹信息存入到mongdb
                    DeviceCoordinateModel deviceCoordinateModel = JSONObject.toJavaObject(info,DeviceCoordinateModel.class);
                    if(deviceCoordinateModel!=null) {
                        deviceCoordinateModel.setId(jsonObject.getString("id"));
                        deviceCoordinateModel.setCreateTime(new Date());
                        if (StringUtils.isNotEmpty(deviceCoordinateModel.getId())) {
                            DeviceInfo deviceInfo = new DeviceInfo();
                            deviceInfo.setDevice(deviceCoordinateModel.getId());
                            deviceInfo.setLat(deviceCoordinateModel.getLatitude() + "");
                            deviceInfo.setLat(deviceCoordinateModel.getLongitude() + "");
                            deviceInfo.setModifyDate(new Date());
                            deviceInfoService.updateNotNull(deviceInfo);
                        }
                    }
                    //MongoService mongoService = SpringUtil.getBean(MongoServiceImpl.class);
                    //mongoService.saveDeviceCoordinate(deviceCoordinateModel);
                }
            }
            // 设备上线就进行位置定位
            DeviceInfoService deviceInfoService = SpringUtil.getBean(DeviceInfoServiceImpl.class);
            DeviceInfo deviceInfo = deviceInfoService.getByGbId(jsonObject.getString("id"));
            if (null != deviceInfo) {
                // 获取全局参数
                SysParamSetService sysParamSetService = SpringUtil.getBean(SysParamSetServiceImpl.class);
                SysParamSet sysParamSet = sysParamSetService.pick();
                if (null == deviceInfo.getSubscribeLocationFlag()
                        || (null != sysParamSet.getPositionSwitchFlag()
                        && !sysParamSet.getPositionSwitchFlag().equals(deviceInfo.getSubscribeLocationFlag()))) {
                    // 开始发送位置订阅信息
                    if (sysParamSet.getPositionSwitchFlag().booleanValue()) {
                        // 定位位置信息
                        boolean instructFlag = gb28181Service.subscribeAllLocation(jsonObject.getString("id"));
                        if (instructFlag) {
                            DeviceInfo updateDeviceInfo = new DeviceInfo();
                            updateDeviceInfo.setSubscribeLocationFlag(Boolean.TRUE);
                            updateDeviceInfo.setId(deviceInfo.getId());
                            updateDeviceInfo.setModifyDate(new Date());
                            updateDeviceInfo.setModifyUser("开启位置订阅");
                            deviceInfoService.updateNotNull(updateDeviceInfo);
                        }
                        log.info("开启位置订阅返回标识值:{}",instructFlag);
                    } else {
                        boolean instructFlag = gb28181Service.cancelSubscribeAllLocation(deviceInfo.getDevice());
                        if (instructFlag) {
                            DeviceInfo updateDeviceInfo = new DeviceInfo();
                            updateDeviceInfo.setSubscribeLocationFlag(Boolean.FALSE);
                            updateDeviceInfo.setId(deviceInfo.getId());
                            updateDeviceInfo.setModifyDate(new Date());
                            updateDeviceInfo.setModifyUser("取消位置订阅");
                            deviceInfoService.updateNotNull(updateDeviceInfo);
                        }
                        log.info("取消位置订阅返回标识值:{}",instructFlag);
                    }
                }
            }
            log.info("设备收到上下线订阅{}信息,处理结果为:{}",(jsonObject.getString("catalog").equals(Constants.DEVICE_STATUS_ONLINE)?"上线":"下线"),bol);
        });

    }

    @OnClose
    public void onClose() {
        log.info("[websocket->{}] 上下线订阅退出连接",deviceStatusWsUrl2);
        log.info("客户端已关闭!");
        log.info("开始尝试重新上下线订阅连接(次数->{})...",retryNum);
        Boolean closeRetryOk = false;
        while (true) {
            try {
                Thread.sleep(300*1000);
                WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer();
                DeviceStatusWebsocketConfig deviceStatusWebsocketConfig = new DeviceStatusWebsocketConfig();
                webSocketContainer.connectToServer(deviceStatusWebsocketConfig, new URI(deviceStatusWsUrl2));
                retryNum++;
                closeRetryOk=true;
            } catch (Exception e) {
                closeRetryOk =false;
                log.info("上下线订阅重新连接失败,请检查网络!");
            }
            if(closeRetryOk==true) {
                break;
            }else {
                try {
                    Thread.sleep(300 * 1000);
                } catch (Exception e2) {
                    log.error("", e2);
                }
            }
        }
    }

    @OnError
    public void onError(Throwable ex) {
        log.error("[websocket->{}] 上下线订阅连接错误={}",deviceStatusWsUrl2,ex.getMessage());
        log.error("上下线订阅websocket即将断开连接!");
        Boolean errorRetryOk = false;
        while (true) {
            try {
                log.info("客户端已关闭!");
                log.info("开始尝试重新上下线订阅连接(次数->{})...", retryNum);
                WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer();
                DeviceStatusWebsocketConfig deviceStatusWebsocketConfig = new DeviceStatusWebsocketConfig();
                webSocketContainer.connectToServer(deviceStatusWebsocketConfig, new URI(deviceStatusWsUrl2));
                retryNum++;
                errorRetryOk = true;
            } catch (Exception e) {
                errorRetryOk = false;
                log.info("上下线订阅重新启动websocket连接失败!");
            }
            if(errorRetryOk==true) {
                break;
            }else {
                try {
                    Thread.sleep(300 * 1000);
                } catch (Exception e2) {
                    log.error("", e2);
                }
            }
        }
    }
}
